Skip to content

Add support for PEP 661 (sentinels)#21647

Open
edgarrmondragon wants to merge 14 commits into
python:masterfrom
edgarrmondragon:sentinels-reloaded
Open

Add support for PEP 661 (sentinels)#21647
edgarrmondragon wants to merge 14 commits into
python:masterfrom
edgarrmondragon:sentinels-reloaded

Conversation

@edgarrmondragon

Copy link
Copy Markdown
Contributor

@github-actions

This comment has been minimized.

Signed-off-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

d-v-b added a commit to d-v-b/zarr-python that referenced this pull request Jul 5, 2026
d-v-b's call: PEP 661 is Final, ty already types the sentinel spelling
exactly, mypy support is in review (python/mypy#21647) and treated as
imminent, and pyright has a known-good version — so use the standard
sentinel today rather than carrying the enum stopgap.

- UNSET is now typing_extensions.Sentinel("UNSET"), used directly in
  type expressions (tuple[str | None, ...] | UNSET); the UnsetType
  companion enum is gone from the API.
- typing_extensions floor bumped to 4.14 (where Sentinel arrived).
- CI pins pyright==1.1.404, the last version before the class-attribute
  sentinel regression (microsoft/pyright#11115); pyproject documents the
  same pin for local runs. 0 errors on the pin; ty checks the sentinel
  fields clean (its 2 remaining diagnostics are its incomplete PEP 728
  extra_items write support, unrelated).
- Known short-term cost, accepted deliberately: mypy-checked consumers
  need cast/type-ignore at narrowing sites until mypy#21647 merges, and
  contributors' Pylance may show phantom Unknowns until the pyright fix
  ships. Recorded in _sentinel.py and the changelog.
- The pydantic native-introspection test reverts to documenting that
  introspection is unsupported (pydantic 2.13 cannot schema a Sentinel);
  the delegation patterns are unaffected.

Assisted-by: ClaudeCode:claude-fable-5
d-v-b added a commit to d-v-b/zarr-python that referenced this pull request Jul 8, 2026
The zarr-metadata model layer that zarr now depends on is unreleased, and
the previous wiring only covered uv project flows, breaking everything else:

- The floor 'zarr-metadata>=0.4.0' is unresolvable from PyPI (only <0.4.0
  exists), failing every hatch env (test matrix, doctests, benchmarks,
  hypothesis, min_deps, upstream) and the readthedocs build. The floor now
  names the newest release (>=0.3) with a TODO to bump at release time, and
  each non-uv flow installs the in-tree package explicitly: hatch envs get a
  '{root:uri}/packages/zarr-metadata' direct reference (repeated per env,
  since hatch replaces extra-dependencies on inheritance), readthedocs gets
  an extra pip install step.

- uv workspace membership made 'uv sync' inside packages/zarr-metadata
  resolve the whole workspace, dragging zarr's requires-python (>=3.12) into
  the subpackage's own CI, which tests down to 3.11. The workspace is now a
  plain editable path source, restoring the subpackage's independence.

- min_deps pins typing_extensions==4.16.* (was 4.14.*): 4.16 is the
  effective minimum because zarr-metadata requires it for sentinel pickling.

Also fixes the Lint (mypy) findings in the new tests — a bare generic Array
annotation, stale type-ignores, and two sentinel comparisons mypy cannot
narrow (python/mypy#21647) — and renames the changelog entries to the PR
number (4129) required by the changelog check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@JelleZijlstra JelleZijlstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to edit mypy/server/deps.py to properly record some dependencies. Codex found this which seems correct:

A sentinel literal now contains the defining symbol’s fullname, but [visit_literal_type()](https://github.com/python/mypy/blob/acfbf461408a091ca4494e0c0ac7eba9aded35c1/mypy/server/deps.py#L1091-L1092) only records the fallback-type dependency. In a reproducer where mod.MISSING changes from Sentinel("MISSING") to 1, the daemon does not reanalyze def f(x: MISSING). It retains the stale sentinel annotation and reports that the integer argument is incompatible, rather than reporting that mod.MISSING is no longer a valid type. The visitor should add a trigger for [SentinelValue.fullname](https://github.com/python/mypy/blob/acfbf461408a091ca4494e0c0ac7eba9aded35c1/mypy/types.py#L101-L105).

- name: Setup tox environment
run: |
tox run -e ${{ matrix.toxenv }} --notest
- name: Install local librt in tox environment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need a coordinated librt release in order to publish this. I don't believe I have the powers to do that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think someone with write access to the librt repo needs to run a script once this PR lands on master

Comment thread mypy/semanal.py
return not rv.node.is_enum
if isinstance(rv.node, Var):
if rv.node.is_sentinel:
return True

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect, it causes us to treat every sentinel reassignment as an alias.

Something like this:

MISSING = Sentinel("MISSING")
ALIAS = MISSING

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, given this text from the PEP:

If the name passed to sentinel() does not match the name the object is assigned to, type checkers should emit an error.

should this cause mypy to fail then?

MISSING = Sentinel("MISSING")
ALIAS = MISSING  # error: ...?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're likely dropping that requirement from the spec. I think this should be fine.

@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants